package com.ch.fastbuilder.model;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.sql.DataSource;

import org.apache.commons.lang.StringUtils;

import com.ch.fastbuilder.common.GenerationType;
import com.ch.fastbuilder.common.SpringContextUtil;
import com.ch.sys.utils.ParamMap;
import com.jolbox.bonecp.BoneCPDataSource;

public class BaseModel extends HashMap<String, Object> {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	protected String tableName;
	protected String primaryKey = "id";
	protected GenerationType generationType;
	protected String sql;
	protected String where, and, or, orderBy;
	protected String join;
	protected Integer offset, limit;
	protected Map<String, Object> params = new HashMap<String, Object>();
	protected static String insertTemplateSQL = "INSERT INTO {0}({1}) VALUES({2})";
	protected static String updateTemplateSQL = "UPDATE {0} SET {1} WHERE {2} = {3}";
	protected static String deleteTemplateSQL = "DELETE FROM {0} WHERE {1} = {2}";
	protected static String getTemplateSQL = "SELECT {0} FROM {1} WHERE {2} = {3}";
	protected static String selectTemplateSQL = "SELECT {0} FROM {1}{2}";
	protected static String countTemplateSQL = "SELECT COUNT(0) FROM {0}{1}";
	protected static String selectAutoIdSQL = "select @@IDENTITY";
	protected static String selectPageForOracleSQL = "SELECT {0} FROM (SELECT ROWNUM rn, t1.* FROM ({1}) t1 WHERE ROWNUM  <= :endIndex) t2 where t2.rn > :startIndex";
	
	protected static Map<String, String> keywordMaps = new HashMap<String, String>();
	
	protected String strColumns = null;
	protected List<String> columns = new ArrayList<String>();
	
	protected void setPages() {
		if(!this.params.containsKey("pageIndex") || !this.params.containsKey("pageSize")) return;
		
		Integer pageIndex = Integer.parseInt(this.params.get("pageIndex").toString());
		Integer pageSize = Integer.parseInt(this.params.get("pageSize").toString());
		
		int offset = (pageIndex-1) * pageSize;
		int limit = pageSize;
		
		this.params.put("offset", offset);
		this.params.put("limit", limit);
		this.params.remove("pageIndex");
		this.params.remove("pageSize");
	}

	protected static void copyKeyValue(Model source, Model target) {
		for(String key : source.keySet()) {
			target.put(key, source.get(key));
		}
	}
	
	protected static <T extends Model> List<T> copyKeyValue(List<Model> source, Class<T> classType) {
		List<T> targets = new ArrayList<T>();
		try {
			for(Model model : source) {
				T target = classType.newInstance();
				for(String key : model.keySet()) {
					target.put(key, model.get(key));
				}
				
				targets.add(target);
			}
		} catch(Exception e) {
			throw new RuntimeException(e);
		}
		
		return targets;
	}
	
	protected static void initKeywords() {
		if(keywordMaps.size() > 0) return;
		keywordMaps.put("order", "`order`");
	}
	
	protected static String formatColumnName(String columnName) {
		initKeywords();
		if(keywordMaps.containsKey(columnName)) {
			return keywordMaps.get(columnName);
		}
		
		return columnName;
	}
	
	protected void setColumns(String __columns) {
		strColumns = __columns;
		
		String[] cList = __columns.split(",");
		for (String column : cList) {
			columns.add(column.trim());
		}
	}
	
	protected void setColumns(String... __columns) {
		StringBuffer sbColumns = new StringBuffer();
		for(String column : __columns) {
			column = column.trim();
			columns.add(column);
			sbColumns.append(column).append(",");
		}
		
		sbColumns.deleteCharAt(sbColumns.length() - 1);
		strColumns = sbColumns.toString();
	}
	
	public GenerationType getGenerationType() {
		return generationType;
	}

	public void setGenerationType(GenerationType GenerationType) {
		this.generationType = GenerationType;
	}

	protected String getTableName() {
		return tableName;
	}

	protected void setTableName(String tableName) {
		this.tableName = tableName;
	}

	protected String getPrimaryKey() {
		return primaryKey;
	}

	protected void setPrimaryKey(String primaryKey) {
		this.primaryKey = primaryKey;
	}

	protected String getWhere() {
		return where;
	}

	protected void setWhere(String where) {
		this.where = where;
	}

	protected Map<String, Object> getParams() {
		return params;
	}

	protected void setParams(Map<String, Object> params) {
		this.params.putAll(params);
	}

	protected String getJoin() {
		return join;
	}

	protected void setJoin(String join) {
		this.join = join;
	}

	protected String getAnd() {
		return and;
	}

	protected void setAnd(String and) {
		this.and = and;
	}

	protected String getOr() {
		return or;
	}

	protected void setOr(String or) {
		this.or = or;
	}
	
	public String getOrderBy() {
		return orderBy;
	}

	public void setOrderBy(String orderBy) {
		this.orderBy = orderBy;
	}

	protected String getSql() {
		return sql;
	}

	protected void setSql(String sql) {
		this.sql = sql;
	}
	
	public String getString(String key){
		if(this.get(key) == null){
			return null;
		}
		return super.get(key).toString();
	}
	
	public Integer getInt(String key){
		Object value = this.get(key);
		if("".equals(value) || value == null)return null;
		
		return Integer.parseInt(value.toString());
	} 
	
	public Long getLong(String key){
		Object value = this.get(key);
		if("".equals(value) || value == null)return null;
		
		return Long.parseLong(value.toString());
	} 
	
	public Double getDouble(String key){
		Object value = this.get(key);
		if("".equals(value) || value == null)return null;
		return Double.parseDouble(this.getString(key));
	}
	
	public Short getShort(String key){
		Object value = this.get(key);
		if("".equals(value) || value == null)return null;
		return Short.parseShort(this.getString(key));
	}
	
	public Byte getByte(String key){
		Object value = this.get(key);
		if("".equals(value) || value == null)return null;
		return Byte.parseByte(this.getString(key));
	}
	
	public Float getFloat(String key){
		return Float.parseFloat(this.getString(key));
	}
	
	public Boolean getBool(String key){
		return Boolean.parseBoolean(this.getString(key));
	}
	
	@SuppressWarnings("unchecked")
	public <T> T get(String key, Class<T> classType) {
		return (T)this.get(key);
	}
}
